package safe

//适用于读多写少的map,线程安全的map，仿照sync.Map
import (
	"errors"
	"sync"
)

// type readOnlyMap[K Key, G any] struct {
// 	m map[K]*G
// }

// key的类型
type Key interface {
	int64 | int32 | int16 | int8 | uint64 | uint32 | uint16 | uint8 | int | uint | string
}

// Map 点名对应的map， 原理使用双map技术，使用的永远是只读的map，有增，删，改会重建readonly map
type Map[K Key, G any] struct {
	//read atomic.Value
	readonly map[K]*G
	sync.Mutex
}

// 新建一个默认的
func NewMap[K Key, G any]() *Map[K, G] {
	m := new(Map[K, G])
	m.Reset()
	return m
}

// Reset 复位
func (m *Map[K, G]) Reset() {
	m.readonly = map[K]*G{} //指针赋值是原子操作的，内容不是原子操作
}

// Get 获取一个测点
func (m *Map[K, G]) Get(key K) (value *G) {
	return m.readonly[key]
}

// Gets 获取一批
func (m *Map[K, G]) Gets(keys []K) (values []*G) {
	kv := m.readonly

	values = make([]*G, len(keys))
	for i := range keys {
		values[i] = kv[keys[i]]
	}
	return
}

// KeyValues 获取键值对
func (m *Map[K, G]) KeyValues() (keys []K, values []*G) {
	kv := m.readonly

	l := len(kv)
	keys = make([]K, l)
	values = make([]*G, l)
	i := 0
	for key, value := range kv {
		keys[i] = key
		values[i] = value
		i++
	}

	return
}

// KeyValues 获取键值对
func (m *Map[K, G]) Values() (values []*G) {
	kv := m.readonly

	l := len(kv)
	values = make([]*G, l)
	i := 0
	for _, value := range kv {
		values[i] = value
		i++
	}

	return
}

// Set 设置一个
func (m *Map[K, G]) Set(key K, value *G) {
	m.Lock()
	defer m.Unlock()
	kv := m.readonly

	nm := map[K]*G{}
	for k, v := range kv {
		if k == key {
			nm[key] = value
			continue
		}
		nm[k] = v
	}
	nm[key] = value
	m.readonly = nm
}

// Sets 设置一个
func (m *Map[K, G]) Sets(keys []K, values []*G) (err error) {
	m.Lock()
	defer m.Unlock()
	kv := m.readonly

	if len(keys) != len(values) {
		err = errors.New("the size is not math between keys and values")
		return
	}

	nm := map[K]*G{}
	for k, v := range kv {
		nm[k] = v
	}
	for i := range keys {
		nm[keys[i]] = values[i]
	}
	m.readonly = nm
	return
}

// Delete 删除一个元素
func (m *Map[K, G]) Delete(key K) {
	m.Lock()
	defer m.Unlock()
	kv := m.readonly

	nm := map[K]*G{}
	for k, v := range kv {
		if k == key {
			continue
		}
		nm[k] = v
	}
	m.readonly = nm
}

// SetMap 设置MAP
func (m *Map[K, G]) SetMap(nm map[K]*G) {
	m.Lock()
	defer m.Unlock()
	m.readonly = nm
}

func (m *Map[K, G]) GetMap() map[K]*G {
	return m.readonly
}
